home *** CD-ROM | disk | FTP | other *** search
- #define RULES_C
- #include "Rules.h"
- #undef RULES_C
-
-
- #pragma segment More
-
-
- Field _neighbour [kFields+1] [kDirections+1] =
- {
- { 0, 0, 0, 0, 0, 0, 0 }, /* 0 ::= not on board */
- { 2, 7, 6, 0, 0, 0, 0 }, /* 1 */
- { 3, 8, 7, 1, 0, 0, 0 }, /* 2 */
- { 4, 9, 8, 2, 0, 0, 0 }, /* 3 */
- { 5, 10, 9, 3, 0, 0, 0 }, /* 4 */
- { 0, 11, 10, 4, 0, 0, 0 }, /* 5 */
- { 7, 13, 12, 0, 0, 1, 0 }, /* 6 */
- { 8, 14, 13, 6, 1, 2, 0 }, /* 7 */
- { 9, 15, 14, 7, 2, 3, 0 }, /* 8 */
- { 10, 16, 15, 8, 3, 4, 0 }, /* 9 */
- { 11, 17, 16, 9, 4, 5, 0 }, /* 10 */
- { 0, 18, 17, 10, 5, 0, 0 }, /* 11 */
- { 13, 20, 19, 0, 0, 6, 0 }, /* 12 */
- { 14, 21, 20, 12, 6, 7, 0 }, /* 13 */
- { 15, 22, 21, 13, 7, 8, 0 }, /* 14 */
- { 16, 23, 22, 14, 8, 9, 0 }, /* 15 */
- { 17, 24, 23, 15, 9, 10, 0 }, /* 16 */
- { 18, 25, 24, 16, 10, 11, 0 }, /* 17 */
- { 0, 26, 25, 17, 11, 0, 0 }, /* 18 */
- { 20, 28, 27, 0, 0, 12, 0 }, /* 19 */
- { 21, 29, 28, 19, 12, 13, 0 }, /* 20 */
- { 22, 30, 29, 20, 13, 14, 0 }, /* 21 */
- { 23, 31, 30, 21, 14, 15, 0 }, /* 22 */
- { 24, 32, 31, 22, 15, 16, 0 }, /* 23 */
- { 25, 33, 32, 23, 16, 17, 0 }, /* 24 */
- { 26, 34, 33, 24, 17, 18, 0 }, /* 25 */
- { 0, 35, 34, 25, 18, 0, 0 }, /* 26 */
- { 28, 36, 0, 0, 0, 19, 0 }, /* 27 */
- { 29, 37, 36, 27, 19, 20, 0 }, /* 28 */
- { 30, 38, 37, 28, 20, 21, 0 }, /* 29 */
- { 31, 39, 38, 29, 21, 22, 0 }, /* 30 */
- { 32, 40, 39, 30, 22, 23, 0 }, /* 31 */
- { 33, 41, 40, 31, 23, 24, 0 }, /* 32 */
- { 34, 42, 41, 32, 24, 25, 0 }, /* 33 */
- { 35, 43, 42, 33, 25, 26, 0 }, /* 34 */
- { 0, 0, 43, 34, 26, 0, 0 }, /* 35 */
- { 37, 44, 0, 0, 27, 28, 0 }, /* 36 */
- { 38, 45, 44, 36, 28, 29, 0 }, /* 37 */
- { 39, 46, 45, 37, 29, 30, 0 }, /* 38 */
- { 40, 47, 46, 38, 30, 31, 0 }, /* 39 */
- { 41, 48, 47, 39, 31, 32, 0 }, /* 40 */
- { 42, 49, 48, 40, 32, 33, 0 }, /* 41 */
- { 43, 50, 49, 41, 33, 34, 0 }, /* 42 */
- { 0, 0, 50, 42, 34, 35, 0 }, /* 43 */
- { 45, 51, 0, 0, 36, 37, 0 }, /* 44 */
- { 46, 52, 51, 44, 37, 38, 0 }, /* 45 */
- { 47, 53, 52, 45, 38, 39, 0 }, /* 46 */
- { 48, 54, 53, 46, 39, 40, 0 }, /* 47 */
- { 49, 55, 54, 47, 40, 41, 0 }, /* 48 */
- { 50, 56, 55, 48, 41, 42, 0 }, /* 49 */
- { 0, 0, 56, 49, 42, 43, 0 }, /* 50 */
- { 52, 57, 0, 0, 44, 45, 0 }, /* 51 */
- { 53, 58, 57, 51, 45, 46, 0 }, /* 52 */
- { 54, 59, 58, 52, 46, 47, 0 }, /* 53 */
- { 55, 60, 59, 53, 47, 48, 0 }, /* 54 */
- { 56, 61, 60, 54, 48, 49, 0 }, /* 55 */
- { 0, 0, 61, 55, 49, 50, 0 }, /* 56 */
- { 58, 0, 0, 0, 51, 52, 0 }, /* 57 */
- { 59, 0, 0, 57, 52, 53, 0 }, /* 58 */
- { 60, 0, 0, 58, 53, 54, 0 }, /* 59 */
- { 61, 0, 0, 59, 54, 55, 0 }, /* 60 */
- { 0, 0, 0, 60, 55, 56, 0 } /* 61 */
- };
-
- unsigned char _distance [kFields+1] [kDirections] =
- {
- { 0, 0, 0, 0, 0, 0 }, /* 0 */
- { 5, 9, 5, 1, 1, 1 }, /* 1 */
- { 4, 8, 6, 2, 1, 1 }, /* 2 */
- { 3, 7, 7, 3, 1, 1 }, /* 3 */
- { 2, 6, 8, 4, 1, 1 }, /* 4 */
- { 1, 5, 9, 5, 1, 1 }, /* 5 */
- { 6, 8, 4, 1, 1, 2 }, /* 6 */
- { 5, 8, 5, 2, 2, 2 }, /* 7 */
- { 4, 7, 6, 3, 2, 2 }, /* 8 */
- { 3, 6, 7, 4, 2, 2 }, /* 9 */
- { 2, 5, 8, 5, 2, 2 }, /* 10 */
- { 1, 4, 8, 6, 2, 1 }, /* 11 */
- { 7, 7, 3, 1, 1, 3 }, /* 12 */
- { 6, 7, 4, 2, 2, 3 }, /* 13 */
- { 5, 7, 5, 3, 3, 3 }, /* 14 */
- { 4, 6, 6, 4, 3, 3 }, /* 15 */
- { 3, 5, 7, 5, 3, 3 }, /* 16 */
- { 2, 4, 7, 6, 3, 2 }, /* 17 */
- { 1, 3, 7, 7, 3, 1 }, /* 18 */
- { 8, 6, 2, 1, 1, 4 }, /* 19 */
- { 7, 6, 3, 2, 2, 4 }, /* 20 */
- { 6, 6, 4, 3, 3, 4 }, /* 21 */
- { 5, 6, 5, 4, 4, 4 }, /* 22 */
- { 4, 5, 6, 5, 4, 4 }, /* 23 */
- { 3, 4, 6, 6, 4, 3 }, /* 24 */
- { 2, 3, 6, 7, 4, 2 }, /* 25 */
- { 1, 2, 6, 8, 4, 1 }, /* 26 */
- { 9, 5, 1, 1, 1, 5 }, /* 27 */
- { 8, 5, 2, 2, 2, 5 }, /* 28 */
- { 7, 5, 3, 3, 3, 5 }, /* 29 */
- { 6, 5, 4, 4, 4, 5 }, /* 30 */
- { 5, 5, 5, 5, 5, 5 }, /* 31 */
- { 4, 4, 5, 6, 5, 4 }, /* 32 */
- { 3, 3, 5, 7, 5, 3 }, /* 33 */
- { 2, 2, 5, 8, 5, 2 }, /* 34 */
- { 1, 1, 5, 9, 5, 1 }, /* 35 */
- { 8, 4, 1, 1, 2, 6 }, /* 36 */
- { 7, 4, 2, 2, 3, 6 }, /* 37 */
- { 6, 4, 3, 3, 4, 6 }, /* 38 */
- { 5, 4, 4, 4, 5, 6 }, /* 39 */
- { 4, 4, 4, 5, 6, 5 }, /* 40 */
- { 3, 3, 4, 6, 6, 4 }, /* 41 */
- { 2, 2, 4, 7, 6, 3 }, /* 42 */
- { 1, 1, 4, 8, 6, 2 }, /* 43 */
- { 7, 3, 1, 1, 3, 7 }, /* 44 */
- { 6, 3, 2, 2, 4, 7 }, /* 45 */
- { 5, 3, 3, 3, 5, 7 }, /* 46 */
- { 4, 3, 3, 4, 6, 6 }, /* 47 */
- { 3, 3, 3, 5, 7, 5 }, /* 48 */
- { 2, 2, 3, 6, 7, 4 }, /* 49 */
- { 1, 1, 3, 7, 7, 3 }, /* 50 */
- { 6, 2, 1, 1, 4, 8 }, /* 51 */
- { 5, 2, 2, 2, 5, 8 }, /* 52 */
- { 4, 2, 2, 3, 6, 7 }, /* 53 */
- { 3, 2, 2, 4, 7, 6 }, /* 54 */
- { 2, 2, 2, 5, 8, 5 }, /* 55 */
- { 1, 1, 2, 6, 8, 4 }, /* 56 */
- { 5, 1, 1, 1, 5, 9 }, /* 57 */
- { 4, 1, 1, 2, 6, 8 }, /* 58 */
- { 3, 1, 1, 3, 7, 7 }, /* 59 */
- { 2, 1, 1, 4, 8, 6 }, /* 60 */
- { 1, 1, 1, 5, 9, 5 } /* 61 */
- };
-
-
-
- // InitRules MUST be called before the following two tables can be used.
-
- Boolean _neighbours [kFields+1] [kFields+1];
- Arrow _direction [kFields+1] [kFields+1];
-
-
-
- void
- InitRules (void)
- {
- Field f1, f2;
- short d;
-
- for (f1 = 0; f1 <= kFields; f1++)
- {
- for (f2 = 0; f2 <= kFields; f2++)
- {
- _neighbours[f1][f2] = false;
- _direction[f1][f2] = down;
-
- for (d = right; d < down; d++)
- {
- if (Neighbour (f1, d) == f2)
- {
- _neighbours[f1][f2] = true;
- _direction[f1][f2] = d;
- }
- }
- }
- }
- }
-
-
-
- short
- BallsWon (BoardPtr board, short player)
- {
- return board->loot[player-1][0];
- }
-
-
-
- void
- ResetBoard (BoardPtr b)
- {
- short f, p, q;
-
- for (p = 0; p < kPlayers; p++)
- for (q = 0; q <= kVictory; q++)
- b->loot[p][q] = 0;
-
- switch (gTheGame.Players)
- {
- default:
- case 2:
- for (f = 1; f <= 61; f++)
- {
- b->field[f] = empty;
-
- if (f <= 16 && f != 12 && f != 13)
- b->field[f] = blak;
- else if (f >= 46 && f != 49 && f != 50)
- b->field[f] = whit;
- }
- break;
- case 3:
- for (f = 1; f <= 61; f++)
- {
- b->field[f] = empty;
-
- if (Distance (f, topleft) <= 2 && Distance (f, topright) <= 2)
- b->field[f] = grin;
- else if (Distance (f, right) <= 2 && Distance (f, botright) <= 2)
- b->field[f] = blak;
- else if (Distance (f, botleft) <= 2 && Distance (f, left) <= 2)
- b->field[f] = whit;
- }
- break;
- }
- }
-
-
-
- Field
- LocToField (short h, short v)
- {
- short r;
-
- if (h < 0 || v < 0)
- return 0;
-
- switch (v / gSet.FieldHeight)
- {
- case 0:
- if ((r = h / gSet.FieldWidth) < 2 || r > 6)
- return 0;
- return r + 1 - 2;
- case 1:
- if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 2 || r > 7)
- return 0;
- return r + 6 - 2;
- case 2:
- if ((r = h / gSet.FieldWidth) < 1 || r > 7)
- return 0;
- return r + 12 - 1;
- case 3:
- if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 1 || r > 8)
- return 0;
- return r + 19 - 1;
- case 4:
- if ((r = h / gSet.FieldWidth) < 0 || r > 8)
- return 0;
- return r + 27 - 0;
- case 5:
- if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 1 || r > 8)
- return 0;
- return r + 36 - 1;
- case 6:
- if ((r = h / gSet.FieldWidth) < 1 || r > 7)
- return 0;
- return r + 44 - 1;
- case 7:
- if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 2 || r > 7)
- return 0;
- return r + 51 - 2;
- case 8:
- if ((r = h / gSet.FieldWidth) < 2 || r > 6)
- return 0;
- return r + 57 - 2;
- default:
- return 0;
- }
- }
-
-
-
- short
- DoMove (BoardPtr board, MovePtr move)
- {
- short player = board->field[move[0]] - 1;
- short victim = DoPropMove (board, move[0], move[3]);
-
- if (victim != empty)
- {
- board->loot[player][0]++;
- board->loot[player][board->loot[player][0]] = victim;
-
- return ball_down;
- }
- return normal_move;
- }
-
-
-
- // returns the id of the player whose ball is pushed off, or empty if none is pushed off
-
- short
- DoPropMove (BoardPtr board, Field f, Arrow direction)
- {
- Field toField;
- short moveResult;
-
- if (board->field[f] == empty) // stopcondition 1: empty field
- return empty;
-
- toField = Neighbour (f, direction);
- moveResult = DoPropMove (board, toField, direction); // recursive call
- if (toField)
- board->field[toField] = board->field[f];
- else
- return board->field[f]; // stopcondition 2: ball over the edge
-
- board->field[f] = empty;
-
- return moveResult;
- }
-
-
-
- short
- DoFlicheMove (BoardPtr board, MovePtr move)
- {
- # define DOMOVE(F,D) board->field [Neighbour (F, D)] = board->field [F], board->field [F] = empty
-
- DOMOVE (move[0], move[3]);
-
- DOMOVE (move[1], move[3]);
-
- if (move[2])
- DOMOVE (move[2], move[3]);
-
- return normal_move;
- }
-
-
-
- Boolean
- ValidMove (BoardPtr board, MovePtr move)
- {
- short pro, contra, player = board->field[*move];
- short f, direction = move[3];
-
- if (player == empty || ! Neighbour (*move, direction) || direction == down)
- return false;
-
- for ( f = *move, pro = 1;
- board->field[Neighbour (f, direction)] == player;
- f = Neighbour (f, direction)
- )
- pro++;
-
- f = Neighbour (f, direction);
-
- if (board->field[f] == empty)
- return pro <= 3 && f != 0;
-
- for ( contra = 1;
- board->field[Neighbour (f, direction)] != empty
- && board->field[Neighbour (f, direction)] != player;
- f = Neighbour (f, direction)
- )
- contra++;
-
- f = Neighbour (f, direction);
-
- return pro <= 3 && pro > contra && board->field[f] == empty;
- }
-
-
-
- // This function calls ValidFlicheSorted with a sorted local copy of the fields,
- // so the ordering of the balls is unchanged.
- // This splitting of ValidFliche in two functions makes calling it
- // more efficient in case it is known in advance the balls ARE sort3 ordered,
- // which is the case for fields generated by the computer players.
- // This function can be used for fliches generated by human players,
- // since these are not necessarily sorted */
-
- Boolean
- ValidFliche (BoardPtr board, FieldsPtr f)
- {
- Field sf[4];
-
- * ((long *) (& sf)) = *((long *) f);
-
- // Use a sorted ball selection, with 0 (empty) at the end.
-
- sort3 (sf);
-
- return ValidFlicheSorted (board, sf);
- }
-
-
-
- Boolean
- ValidFlicheSorted (BoardPtr board, FieldsPtr sf)
- {
- // Precondition: the fields should be ordered, with 0 (empty) at the end.
-
- if ( sf[1] && board->field[sf[0]] != board->field[sf[1]]
- || sf[2] && board->field[sf[0]] != board->field[sf[2]]
- )
- return false;
-
- if ( (sf[1] && ! Neighbours (sf[0], sf[1]))
- || (sf[2] && ! Neighbours (sf[1], sf[2]))
- )
- return false;
-
- if (sf[2] && (Direction (sf[0], sf[1]) != Direction (sf[1], sf[2])))
- return false;
-
- return true;
- }
-
-
-
- // Same as for ValidFliche: create a local copy to sort, and call ValidFlicheMoveSorted.
-
- Boolean
- ValidFlicheMove (BoardPtr board, MovePtr move)
- {
- MoveData sf;
-
- * ((long *) (& sf)) = *((long *) move);
-
- sort3 (sf);
- return ValidFlicheSorted (board, sf) && ValidFlicheMoveSorted (board, sf);
- }
-
-
-
- Boolean
- ValidFlicheMoveSorted (BoardPtr board, MovePtr move)
- {
- short moveDirection = move[3];
-
- // Precondition: the fields should be ordered, with 0 (empty) fields at the end.
- // Precondition: the fliche should be valid.
-
- if (! ValidFlicheSorted (board, (FieldsPtr) move))
- return false;
-
- // Test for moving to an occupied field.
-
- if ( ( board->field[Neighbour (move[0], moveDirection)] != empty)
- || (move[1] && board->field[Neighbour (move[1], moveDirection)] != empty)
- || (move[2] && board->field[Neighbour (move[2], moveDirection)] != empty)
- )
- return false;
-
- // Test for suicide.
-
- if ( ! Neighbour (move[0], moveDirection)
- || move[1] && ! Neighbour (move[1], moveDirection)
- || move[2] && ! Neighbour (move[2], moveDirection)
- )
- return false;
-
- // Test for straightness.
-
- if ( move[1] && Direction (move[0], move[1]) == moveDirection
- || move[1] && Direction (move[0], move[1]) == moveDirection - 3)
- return false;
-
- return true;
- }
-
-
-
- // Sort an array of 3 fields from low to high, but counting zeroes as highest
-
- void
- sort3 (FieldsPtr fields)
- {
- Field tmp;
-
- # define SWAP(X,Y) (tmp = X, X = Y, Y = tmp);
-
- if (fields[0] == 0 || fields[0] > fields[1] && fields[1] != 0) SWAP (fields[0], fields[1]);
- if (fields[1] == 0 || fields[1] > fields[2] && fields[2] != 0) SWAP (fields[1], fields[2]);
- if (fields[0] == 0 || fields[0] > fields[1] && fields[1] != 0) SWAP (fields[0], fields[1]);
- }
-